<template>
  <div>
    <van-nav-bar title="编辑资料" @click-left="$router.back()" left-arrow />
    <!-- 头像修改的区域 -->
    <div class="avatar-box">
      <!-- after-read钩子 -->
      <!-- 它绑定的函数会在选择完文件后调用 -->
      <van-uploader :after-read="afterRead" />
      <van-image round fit="cover" :src="userInfo.photo" />
    </div>
    <!-- 三个cell显示名字,性别,生日 -->
    <van-cell-group>
      <van-cell
        @click="doEditName"
        to="/mine/edit"
        title="名称"
        :value="userInfo.name"
      />
      <van-cell
        @click="popShow = true"
        title="性别"
        :value="userInfo.gender ? '男' : '女'"
      />
      <van-cell @click="showBirthday" title="生日" :value="userInfo.birthday" />
    </van-cell-group>

    <!-- 弹出框 - 用来修改名字 -->
    <!-- v-model绑定的数据是用来控制弹出框的显示和隐藏 -->
    <van-dialog
      @confirm="updateName"
      v-model="nameShow"
      title="修改名字"
      show-cancel-button
    >
      <van-field ref="nameInp" class="name-field" v-model="editName" />
    </van-dialog>

    <van-popup class="genderPop" v-model="popShow" position="bottom">
      <van-nav-bar
        @click-left="popShow = false"
        title="修改性别"
        left-text="取消"
      />
      <van-cell @click="changeGender(1)" title="男" is-link />
      <van-cell @click="changeGender(0)" title="女" is-link />
    </van-popup>

    <van-popup v-model="birthShow" position="bottom" class="birthPop">
      <!-- v-model：用来获取和设置当前时间 -->
      <!-- min-date：用来设置最小能选择的日期 -->
      <!-- max-date：用来设置最大能选择的日期 -->
      <van-datetime-picker
        @cancel="birthShow = false"
        @confirm="editBirth"
        v-model="currentDate"
        type="date"
        title="选择年月日"
        :min-date="minDate"
        :max-date="maxDate"
      />
    </van-popup>

    <div class="crop-box" v-if="cropShow">
      <vueCropper
        ref="cropper"
        :img="cropImg"
        autoCrop
        autoCropWidth="180"
        autoCropHeight="180"
      >
      </vueCropper>
      <van-button @click="doCrop" type="primary">裁剪</van-button>
      <van-button @click="cropShow = false" type="primary">取消</van-button>
    </div>
  </div>
</template>

<script>
import { editUserInfoAPI, changeUserPhotoAPI } from "@/api";
import moment from "moment";
import { VueCropper } from "vue-cropper";

export default {
  components: {
    VueCropper,
  },
  data() {
    return {
      nameShow: false,
      editName: "",
      popShow: false,
      birthShow: false,
      // 选择最小的时间
      minDate: new Date(1949, 9, 1),
      // 选择最大时间
      maxDate: new Date(),
      // 设置默认时间 - 这个无所谓反正到时候都要用代码改
      currentDate: new Date(2021, 0, 17),
      cropShow: false,
      cropImg: "",
    };
  },
  methods: {
    doEditName() {
      // 显示出弹出框(这里仅仅只是改了数据，渲染是异步的，要等这里的同步执行完才去渲染)
      this.nameShow = true;
      // 把名字显示到输入框里
      this.editName = this.userInfo.name;
      // 获得焦点
      //this.$nextTick 函数会在下一次dom更新时调用
      this.$nextTick(() => {
        this.$refs.nameInp.focus();
      });
    },

    // 点击修改名字的弹出框里的确认按钮触发
    async updateName() {
      // 非空判断
      if (this.editName == "") return this.$toast("请输入名字");
      // 调用接口发请求修改资料
      await editUserInfoAPI({ name: this.editName });
      //  此时修改完了,但是要刷新才能看到效果
      //  为了不刷新,我们就应该把修改后的结果自己改动到vuex里
      this.$store.commit("changeUserInfo", {
        // 我们之前的属性都还保留下来
        ...this.userInfo,
        name: this.editName,
      });
    },
    // 修改性别的点击事件
    async changeGender(gender) {
      await editUserInfoAPI({ gender });
      //  此时修改完了,但是要刷新才能看到效果
      //  为了不刷新,我们就应该把修改后的结果自己改动到vuex里
      this.$store.commit("changeUserInfo", {
        // 我们之前的属性都还保留下来
        ...this.userInfo,
        gender,
      });

      // 让弹出层隐藏
      this.popShow = false;
    },

    // 修改生日的点击事件
    async editBirth() {
      // 发请求修改生日
      // 接口要求传递的是字符串，所以你不能直接传currentDate，因为它是日期对象
      // 所以现在我们要把日期对象，改成字符串形式 - "YYYY-MM-DD"
      const birthday = moment(this.currentDate).format("YYYY-MM-DD");
      await editUserInfoAPI({ birthday });

      // 改动到vuex
      this.$store.commit("changeUserInfo", {
        ...this.userInfo,
        birthday,
      });

      // 隐藏弹出层
      this.birthShow = false;
    },

    // 当选择完图片文件调用的钩子
    // 这个钩子有默认的参数
    afterRead(data) {
      // 把选择图片的base64给裁剪绑定的img
      this.cropImg = data.content;
      // 把裁剪容器显示出来
      this.cropShow = true;
    },

    // 点击生日cell的事件
    showBirthday() {
      // 显示出生日
      this.birthShow = true;
      // 把用户的生日赋值给日期选择器的当前日期
      // 注意：vuex里保存的数据是字符串，但是这里要给的是日期对象
      // 所以要转换
      this.currentDate = new Date(this.userInfo.birthday);
    },

    // 裁剪的点击事件
    doCrop() {
      // 这里的参数data就是裁剪后的文件对象
      // 拿到裁剪后的对象是为了上传给服务器
      // 所以这里要发请求
      // ajax不能直接上传文件，要上传文件必须要用到 FormData 这个对象（ajax2.0）
      // 如果jQuery要用 FormData 上传，都还得加两句话contentType:false processData:false
      this.$refs.cropper.getCropBlob(async (data) => {
        // axios本质上发的就是ajax请求，所以肯定也得要FormData
        let fm = new FormData();
        fm.append("photo", data);
        // 直接把FormData作为对象参数传递进去即可
        let res = await changeUserPhotoAPI(fm);
        // console.log(res);// res.data.data.photo 就是服务器返回的图片上传后的地址
        // 发送完请求要更新到vuex里
        this.$store.commit("changeUserInfo", {
          ...this.userInfo,
          photo: res.data.data.photo,
        });
        // 把裁剪区隐藏了
        this.cropShow = false;
      });
    },
  },

  created() {
    this.$store.dispatch("getUserInfo");
  },
  computed: {
    userInfo() {
      return this.$store.state.userInfo;
    },
  },
};
</script>

<style lang="less" scoped>
@width: 120px;
.avatar-box {
  height: @width;
  display: flex;
  justify-content: center;
  align-items: center;

  .van-image {
    width: 100px;
    height: 100px;
  }
}

.van-uploader {
  // 因为只有当绝对定位或者固定定位才不占位置
  // 就能显示图片
  position: absolute;
  z-index: 9999;

  // 因为scoped只能作用于显示在html里的标签,
  // van-uploader这个标签是在插件里,没有显示出来,
  // 所以需要深度监听才能显示出来
  ::v-deep .van-uploader__upload {
    width: 100vw;
    height: @width;
    opacity: 0;
  }
}

.name-field {
  border: 1px solid #ddd;
}

.genderPop {
  height: 160px;
}

.birthPop {
  height: 200px;
}

.crop-box {
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;

  .van-button {
    position: absolute;
    bottom: 0;

    &:last-of-type {
      right: 0;
    }
  }
}
</style>